<template>
  <div class="upload-container">
    <el-upload
      :disabled="isDisabled"
      class="upload-demo mr10 mb15"
      action
      :http-request="handleUploadForm"
      :headers="myHeaders"
      :show-file-list="false"
      :before-upload="beforeUpload"
      :accept="acceptTypes"
      multiple
    >
      <div v-if="url" class="upLoad3dBox">
        <div class="upLoad">
          <i class="el-icon-document-checked cameraIconfont" />
          <div class="model-preview-tip">模型已上传</div>
        </div>
      </div>
      <el-button :disabled="isDisabled"  v-else size="mini" type="primary" v-hasPermi="['merchant:upload:file', 'merchant:upload:image']"
        >点击上传3D模型</el-button
      >
    </el-upload>

    <!-- 3D模型预览区域 -->
    <div v-if="showPreview && modelUrl" class="model-preview-container">
      <h4>模型预览</h4>
      <div ref="modelContainer" class="model-container"></div>
      <div class="preview-controls">
        <el-button size="mini" @click="resetCamera">重置视角</el-button>
        <el-button size="mini" @click="toggleGrid">{{ showGrid ? '隐藏网格' : '显示网格' }}</el-button>
        <el-button size="mini" @click="clearUpload">清空模型</el-button>
      </div>
      <div v-if="modelInfo" class="model-info">
        <p><strong>名称:</strong> {{ modelInfo.name }}</p>
        <p><strong>格式:</strong> {{ modelInfo.format }}</p>
        <p><strong>大小:</strong> {{ modelInfo.size }}</p>
      </div>
    </div>

    <!-- 上传提示 -->
    <div class="upload-tips">
      <p>支持格式: {{ acceptTypes }}</p>
      <p>最大限制: 50MB</p>
      <p>提示: 在预览区使用鼠标左键旋转、滚轮缩放、右键平移</p>
    </div>
  </div>
</template>

<script>
import { threeModuleApi } from '@/api/systemSetting';
import { getToken } from '@/utils/auth';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader';
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

export default {
  name: 'Upload3DModel',
  props: {
    value: {
      type: String,
      default: '',
    },
    showPreview: {
      type: Boolean,
      default: true,
    },
    isDisabled: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      myHeaders: { 'X-Token': getToken() },
      url: '',
      modelUrl: '',
      modelInfo: null,
      acceptTypes: '.gltf,.glb,.obj,.fbx,.stl',

      // Three.js相关
      scene: null,
      camera: null,
      renderer: null,
      controls: null,
      model: null,
      gridHelper: null,
      showGrid: true,
      animationId: null,
      loaders: {
        gltf: new GLTFLoader(),
        glb: new GLTFLoader(),
        obj: new OBJLoader(),
        fbx: new FBXLoader(),
        stl: new STLLoader(),
      },
    };
  },
  watch: {
    value: {
      handler(newVal) {
        if (newVal) {
          this.url = newVal;
          this.modelUrl = newVal;
          if (this.showPreview) {
            this.$nextTick(() => {
              this.initThreeJS();
            });
          }
        } else {
          this.url = '';
          this.modelUrl = '';
          this.modelInfo = null;
        }
      },
      immediate: true,
    },
    modelUrl(newVal) {
      if (newVal && this.showPreview) {
        this.$nextTick(() => {
          if (!this.scene) {
            this.initThreeJS();
          } else {
            this.loadModelForPreview(newVal);
          }
        });
      }
    },
  },
  mounted() {
    if (this.showPreview && this.modelUrl) {
      this.$nextTick(() => {
        this.initThreeJS();
      });
    }
  },
  beforeDestroy() {
    this.cleanupThreeJS();
  },
  methods: {
    // 初始化Three.js场景
    initThreeJS() {
      if (!this.$refs.modelContainer) return;
      
      // 清理之前的场景
      this.cleanupThreeJS();
      
      const container = this.$refs.modelContainer;

      // 创建场景
      this.scene = new THREE.Scene();
      this.scene.background = new THREE.Color(0xf0f0f0);

      // 创建相机
      this.camera = new THREE.PerspectiveCamera(75, container.clientWidth / container.clientHeight, 0.1, 1000);
      this.camera.position.set(5, 5, 5);
      this.camera.lookAt(0, 0, 0);

      // 创建渲染器
      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true,
      });
      this.renderer.setSize(container.clientWidth, container.clientHeight);
      this.renderer.setPixelRatio(window.devicePixelRatio);
      
      // 清除容器内的现有内容
      while (container.firstChild) {
        container.removeChild(container.firstChild);
      }
      container.appendChild(this.renderer.domElement);

      // 添加轨道控制
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);
      this.controls.enableDamping = true;
      this.controls.dampingFactor = 0.05;
      this.controls.screenSpacePanning = true;
      this.controls.minDistance = 1;
      this.controls.maxDistance = 50;

      // 环境光
      const ambientLight = new THREE.AmbientLight(0x404040, 1.5);
      this.scene.add(ambientLight);

      // 方向光
      const directionalLight = new THREE.DirectionalLight(0xffffff, 1.2);
      directionalLight.position.set(5, 15, 10);
      this.scene.add(directionalLight);

      // 添加一个补充光源
      const fillLight = new THREE.DirectionalLight(0xffffff, 0.5);
      fillLight.position.set(-5, 5, 5);
      this.scene.add(fillLight);

      // 添加网格地面
      this.gridHelper = new THREE.GridHelper(10, 10, 0x888888, 0xcccccc);
      this.gridHelper.rotation.x = Math.PI / 2;
      this.scene.add(this.gridHelper);

      // 处理窗口大小变化
      window.addEventListener('resize', this.onWindowResize);

      // 开始渲染循环
      this.animate();

      // 如果已有模型URL，加载模型
      if (this.modelUrl) {
        this.loadModelForPreview(this.modelUrl);
      }
    },

    // 窗口大小调整处理
    onWindowResize() {
      if (!this.camera || !this.renderer || !this.$refs.modelContainer) return;

      const container = this.$refs.modelContainer;
      this.camera.aspect = container.clientWidth / container.clientHeight;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(container.clientWidth, container.clientHeight);
    },

    // 渲染循环
    animate() {
      if (this.renderer && this.scene && this.camera) {
        this.animationId = requestAnimationFrame(this.animate);

        if (this.controls) {
          this.controls.update();
        }

        this.renderer.render(this.scene, this.camera);
      }
    },

    // 清理Three.js资源
    cleanupThreeJS() {
      window.removeEventListener('resize', this.onWindowResize);
      
      if (this.animationId) {
        cancelAnimationFrame(this.animationId);
        this.animationId = null;
      }

      if (this.controls) {
        this.controls.dispose();
        this.controls = null;
      }

      if (this.renderer) {
        this.renderer.dispose();
        this.renderer.forceContextLoss();
        this.renderer = null;
      }

      this.clearModel();
      
      if (this.scene) {
        // 清理场景中的所有对象
        while(this.scene.children.length > 0) { 
          this.scene.remove(this.scene.children[0]); 
        }
        this.scene = null;
      }
    },

    // 上传前验证
    beforeUpload(file) {
      const extension = file.name.split('.').pop().toLowerCase();
      const isValidFormat = ['gltf', 'glb', 'obj', 'fbx', 'stl'].includes(extension);
      const isLt50M = file.size / 1024 / 1024 < 50;

      if (!isValidFormat) {
        this.$message.error('请上传支持的3D模型格式 (gltf, glb, obj, fbx, stl)!');
        return false;
      }
      if (!isLt50M) {
        this.$message.error('模型大小不能超过50MB!');
        return false;
      }

      // 保存文件信息用于预览
      this.modelInfo = {
        name: file.name,
        format: extension.toUpperCase(),
        size: this.formatFileSize(file.size),
        file: file,
      };

      return true;
    },

    // 上传处理
    handleUploadForm(param) {
      const formData = new FormData();
      formData.append('file', param.file);
      formData.append('enable3dView', true);
      const loading = this.$loading({
        lock: true,
        text: '3D模型上传中，请稍候...',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)',
      });

      threeModuleApi(formData)
        .then((res) => {
          loading.close();
          this.url = res.url;
          this.modelUrl = res.url;
          this.$emit('input', this.url);
          this.$emit('upload-success', res);
          this.$message.success('3D模型上传成功');
        })
        .catch((error) => {
          console.error(error);
          loading.close();
          this.$emit('upload-error', error);
          this.$message.error('上传失败: ' + (error.message || '服务器错误'));
        });
    },

    // 加载模型进行预览
    async loadModelForPreview(url) {
      if (!this.scene || !url) return;
      
      try {
        this.clearModel();
        const extension = url.split('.').pop().toLowerCase();
        const loader = this.loaders[extension];
        if (!loader) {
          console.warn('不支持的预览格式:', extension);
          return;
        }

        if (extension === 'gltf' || extension === 'glb') {
          const gltf = await new Promise((resolve, reject) => {
            loader.load(url, resolve, undefined, reject);
          });
          this.model = gltf.scene;
        } else if (extension === 'obj') {
          this.model = await new Promise((resolve, reject) => {
            loader.load(url, resolve, undefined, reject);
          });
        } else if (extension === 'fbx') {
          this.model = await new Promise((resolve, reject) => {
            loader.load(url, resolve, undefined, reject);
          });
        } else if (extension === 'stl') {
          const geometry = await new Promise((resolve, reject) => {
            loader.load(url, resolve, undefined, reject);
          });
          const material = new THREE.MeshPhongMaterial({
            color: 0xaaaaaa,
            specular: 0x111111,
            shininess: 200,
          });
          this.model = new THREE.Mesh(geometry, material);
        }

        if (this.model) {
          this.scene.add(this.model);
          this.centerModel();
        }
      } catch (error) {
        console.error('模型预览加载失败:', error);
        this.$message.error('模型预览加载失败: ' + error.message);
      }
    },

    // 居中显示模型
    centerModel() {
      if (!this.model) return;

      const box = new THREE.Box3().setFromObject(this.model);
      const center = box.getCenter(new THREE.Vector3());
      const size = box.getSize(new THREE.Vector3());

      // 将模型中心移动到原点
      this.model.position.x = -center.x;
      this.model.position.y = -center.y;
      this.model.position.z = -center.z;

      // 自动缩放
      const maxDim = Math.max(size.x, size.y, size.z);
      const scale = 5 / maxDim;
      this.model.scale.multiplyScalar(scale);

      // 更新控制器目标
      if (this.controls) {
        this.controls.target.set(0, 0, 0);
        this.controls.update();
      }
    },

    // 清除当前模型
    clearModel() {
      if (this.model) {
        this.scene.remove(this.model);
        // 释放内存
        if (this.model.geometry) this.model.geometry.dispose();
        if (this.model.material) {
          if (Array.isArray(this.model.material)) {
            this.model.material.forEach((material) => material.dispose());
          } else {
            this.model.material.dispose();
          }
        }
        this.model = null;
        this.$emit('delete')
      }
    },

    // 重置相机视角
    resetCamera() {
      if (this.camera && this.controls) {
        this.camera.position.set(5, 5, 5);
        this.camera.lookAt(0, 0, 0);
        this.controls.target.set(0, 0, 0);
        this.controls.update();
      }
    },

    // 切换网格显示
    toggleGrid() {
      this.showGrid = !this.showGrid;
      if (this.gridHelper) {
        this.gridHelper.visible = this.showGrid;
      }
    },

    // 格式化文件大小
    formatFileSize(bytes) {
      if (bytes === 0) return '0 Bytes';
      const k = 1024;
      const sizes = ['Bytes', 'KB', 'MB', 'GB'];
      const i = Math.floor(Math.log(bytes) / Math.log(k));
      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    },

    // 清空上传
    clearUpload() {
      this.url = '';
      this.modelUrl = '';
      this.modelInfo = null;
      this.$emit('input', '');
      this.$emit('clear-upload');
      
      if (this.showPreview) {
        this.clearModel();
      }
    },
  },
};
</script>

<style scoped>
.upload-container {
  position: relative;
}

.upLoad3dBox {
  position: relative;
  display: inline-block;
}

.upLoad {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 10px;
}

.cameraIconfont {
  font-size: 24px;
  color: #67c23a;
  margin-bottom: 5px;
}

.model-preview-tip {
  font-size: 12px;
  color: #67c23a;
}

.model-preview-container {
  margin-top: 20px;
  padding: 15px;
  border: 1px solid #e6e6e6;
  border-radius: 4px;
  background: #fafafa;
}

.model-preview-container h4 {
  margin: 0 0 10px 0;
  color: #409eff;
}

.model-container {
  width: 100%;
  height: 300px;
  border: 1px solid #ddd;
  border-radius: 4px;
  margin-bottom: 10px;
  overflow: hidden;
}

.preview-controls {
  margin-bottom: 10px;
}

.model-info {
  padding: 10px;
  background: white;
  border-radius: 4px;
  border-left: 3px solid #409eff;
}

.model-info p {
  margin: 5px 0;
  font-size: 12px;
}

.upload-tips {
  margin-top: 10px;
  font-size: 12px;
  color: #909399;
}

.upload-tips p {
  line-height: 10px;
  padding: 5px 0;
  margin: 2px 0;
}
</style>